#pragma once
#include <memory>
#include <string>
#include "nef_common.h"
#include "nef_scope.h"
#include "nef_register_base.h"

#define OWNER_GETTER std::shared_ptr<IxType> (Owner::*F)() const

namespace nef {

class Catalog;


/* Marker interface that exports the specified type
 */
template<typename Type, typename IxType = Type, const char *ContractName = NO_CONTRACT, typename scope = shared>
struct nef_export 
{
	typedef Type owner_t;

	// This constructor will actually register this type
	nef_export()
	{
		//catalog::GlobalCatalog()->AddExport(scope::Scope<Type, IxType>(), ContractName);
		s_registeredExports.push_back(CreateExport(scope::Scope<Type, IxType>(), ContractName));
	}
};

/* Marker interface that describes an export performed by a member function of a specified type
 */
template<typename Owner, typename IxType, OWNER_GETTER, const char *ContractName = NO_CONTRACT, typename scope = shared>
struct nef_export_memfun {};



template<typename T>
struct nef_export_resolver
{
	// Any export definition that is not of type nef_export is an error
	//static_assert(sizeof(T) == 0, "The specified export definition must be of type nef_export or nef_export_memfun");
	static void Resolve(Catalog &cat)
	{
		auto_register<T>(cat);
	}

};

template<typename Type, typename IxType, const char *ContractName, typename scope>
struct nef_export_resolver<nef_export<Type, IxType, ContractName, scope>>
{
	static void Resolve(Catalog &r)
	{
		r.AddPart(scope::Scope<Type, IxType>(), ContractName);
	}
	static void Resolve(Catalog &cat, const Type &)
	{
		//Resolve(cat);
	}
};

template<typename Owner, typename IxType, OWNER_GETTER, const char *ContractName, typename scope>
struct nef_export_resolver<nef_export_memfun<Owner, IxType, F, ContractName, scope>>
{
	static void Resolve(Catalog &cat, const Owner &val)
	{
		// For now, we are forcing that all exports done this way are shared
		auto spVal = (val.*F)();

		cat.AddPart(scope::Scope<Owner, IxType>(spVal), ContractName);
	}
};

}


